package network

import (
	"github.com/wanhuo/GoSocketFrame/common"
	"github.com/wanhuo/GoSocketFrame/protocol"
	"sync"
	"github.com/wanhuo/GoSocketFrame/utils"
	"github.com/gorilla/websocket"
	"errors"
	"net"
	"bytes"
	"encoding/gob"
	"github.com/golang/protobuf/proto"
	"io"
	"fmt"
)

type WebSession struct {
	sockid        uint64
	conn          *websocket.Conn
	writeChan     chan interface{}
	OnClose       func(common.ISession)
	stream        protocol.PacketStream
	iattemper     common.IAttemperEngineSink
	userItem      interface{}
	endSync       sync.WaitGroup //协程结束
	needStopWrite bool           //是否需要主动断开写协程
	isDone        bool           //session是否已经关闭
	bindData      interface{}
	sendList      *protocol.PacketList //将发包改为发送列表
	log           *utils.Logger
	closeType     common.CloseType
}

// 发包
func (self *WebSession) Send(mainId uint16, subId uint16, data []byte) error {
	pkt := protocol.MakePacket(mainId, subId, data)
	if self.isDone {
		return errors.New("session has done")
	}
	self.sendList.Add(pkt)

	return nil
}

// 断开
func (self *WebSession) Close(closeType common.CloseType) {
	self.closeType = closeType

	if !self.isDone {
		self.isDone = true
		// 通知关闭写协程
		self.sendList.Close()
	}
}

// 标示ID
func (self *WebSession) ID() uint64 {
	return self.sockid
}

func (self *WebSession) BindUserItem(item interface{}) {
	self.userItem = item
}

func (self *WebSession) GetBindUserItem() interface{} {
	return self.userItem
}

func (self *WebSession) GetRemoteAddr() string {
	ipstring, _, _ := net.SplitHostPort(self.conn.RemoteAddr().String())
	return ipstring
}

func (self *WebSession) sendThread() {
	var sendList []*protocol.Packet
	for true {
		sendList = sendList[0:0]

		// 复制出队列
		packetList := self.sendList.BeginPick()

		sendList = append(sendList, packetList...)

		self.sendList.EndPick()
		willExit := false
		// 写队列
		for _, p := range sendList {
			if p.MainId == protocol.InvliadPacketMainID {
				goto exitSendLoop
			} else if err := self.stream.Write(p); err != nil {
				willExit = true
				self.log.Errorln("Session 发送数据错误", err)
				break
			}
		}

		if willExit {
			goto exitSendLoop
		}
	}

exitSendLoop:
	self.isDone = true
	self.needStopWrite = false
	self.stream.Close()

	self.endSync.Done()
}

func (self *WebSession) recvThread() {
	for {
		err := utils.SafeCall(func(args ...interface{}) error {
			se, ok := args[0].(*WebSession)
			//从Socket读取封包
			if ok {
				pk, err := se.stream.Read()
				if err != nil {
					//if err == io.EOF {
					//	self.log.Warnln("Session-对端关闭")
					//} else {
					//	self.log.Errorln("Session-错误", err)
					//}
					return err
				}
				if pk.MainId != MainCmd_Network_FrameWork {
					ret := se.iattemper.OnEventTCPNetworkRead(pk.MainId, pk.SubId, pk.Data, se)
					if !ret {
						str := fmt.Sprintf("逻辑层处理错误 %d %d", pk.MainId, pk.SubId)
						return errors.New(str)
					}
				}
				//收到客户端数据 安全连接
				se.SetBindData(KeepAlive_Safe)
			}

			return nil
		}, self)

		if err != nil {
			if err != io.EOF {
				self.log.Errorln("Session", err)
			}
			break
		}
	}

	self.isDone = true
	if self.needStopWrite {
		self.sendList.Close()
	}

	// 通知接收线程ok
	self.endSync.Done()
}

func (self *WebSession) Recv(uint16, uint16, []byte) bool {
	return false
}

func (self *WebSession) existThread() {
	// 等待2个任务结束
	self.endSync.Wait()
	utils.SafeCall(func(args ...interface{}) error {
		se := args[0].(*WebSession)
		if se.closeType == common.CloseType_UpLayer {
			se.iattemper.OnEventTCPNetworkShut(se)
		}
		return nil
	}, self)

	if self.OnClose != nil {
		self.OnClose(self)
	}
}

func (self *WebSession) SetBindData(data interface{}) {
	self.bindData = data
}

func (self *WebSession) GetBindData() interface{} {
	return self.bindData
}

func (self *WebSession) SendPbMessage(mainId uint16, subId uint16, pb proto.Message) error {
	data, err := proto.Marshal(pb)
	if err != nil {
		self.log.Errorln(err)
		return err
	}
	return self.Send(mainId, subId, data)
}

func (self *WebSession) SendGobMessage(mainId uint16, subId uint16, e interface{}) error {
	var netdata bytes.Buffer
	enc := gob.NewEncoder(&netdata)
	if err := enc.Encode(e); err != nil {
		self.log.Errorln(err)
		return err
	}
	return self.Send(mainId, subId, netdata.Bytes())
}

func NewWebSession(sockid uint64, webcon *websocket.Conn, attemper common.IAttemperEngineSink) *WebSession {
	self := &WebSession{
		writeChan:     make(chan interface{}),
		conn:          webcon,
		sockid:        sockid,
		iattemper:     attemper,
		isDone:        false,
		needStopWrite: true,
		bindData:      nil,
		sendList:      protocol.NewPacketList(),
		log:           utils.NewLogger(),
	}

	self.stream = protocol.NewWebStream(self.conn)
	// 布置接收和发送2个任务
	self.endSync.Add(2)

	// 退出线程
	go self.existThread()

	// 接收线程
	go self.recvThread()

	// 发送线程
	go self.sendThread()

	return self
}